SpringBoot打包并结合shell脚本命令部署,重点在分享一个shell程序启动工具,希望能便利工作:
profiles指定不同环境的配置
maven-assembly-plugin打发布压缩包
shenniu_publish.sh程序启动工具
linux上使用shenniu_publish.sh启动程序
示例项目文件结构:
profiles指定不同环境的配置 通常一套程序分为了很多个部署环境:开发,测试,uat,线上 等,要想对这些环境区分配置文件,可以通过两种方式:
通过application.yml
中编码指定profile.active=uat
方式指定
通过pom.xml中profiles来区分
不同环境对应的配置文件夹,人工可以手动在idea勾选生成不同环境的包(推荐)
这里要讲的是第二种,首先在pom.xml
中配置如下内容:
<profiles > <profile > <id > node</id > <properties > <activeProfile > node</activeProfile > <package-name > ${scripts_packageName}</package-name > <boot-main > ${scripts_bootMain}</boot-main > </properties > <activation > <activeByDefault > true</activeByDefault > </activation > </profile > <profile > <id > node1</id > <properties > <activeProfile > node1</activeProfile > <package-name > ${scripts_packageName}</package-name > <boot-main > ${scripts_bootMain}</boot-main > </properties > </profile > <profile > <id > node2</id > <properties > <activeProfile > node2</activeProfile > <package-name > ${scripts_packageName}</package-name > <boot-main > ${scripts_bootMain}</boot-main > </properties > </profile > </profiles >
节点粗解:
properties
:该节点中的节点是可作为参数传递给其他配置文件
,如这里的package-name
节点值就可以在另外的assembly.xml
或者shell脚本
文件中通过${package-name}
获取到,如下shenniu_publish.sh
文件示例:
activeByDefault
:指定默认环境配置文件夹
maven-assembly-plugin打发布压缩包 对于SpringBoot
程序打包,可以分为jar
和war
,这里是jar包;有些场景是配置文件
或者第三方等依赖包不想放到工程jar中,并且把这些文件压缩成一个zip包,方便上传到linux;此时通过maven-assembly-plugin
和maven-jar-plugin
就可以做到,pom.xml
的配置如下:
<plugin > <groupId > org.apache.maven.plugins</groupId > <artifactId > maven-jar-plugin</artifactId > <version > 2.6</version > <configuration > <archive > <addMavenDescriptor > false</addMavenDescriptor > <manifest > <addClasspath > true</addClasspath > <classpathPrefix > lib/</classpathPrefix > <mainClass > ${scripts_bootMain}</mainClass > </manifest > </archive > <excludes > <exclude > **/*.yml</exclude > <exclude > **/*.properties</exclude > <exclude > **/*.xml</exclude > <exclude > **/*.sh</exclude > </excludes > </configuration > <executions > <execution > <id > make-a-jar</id > <phase > compile</phase > <goals > <goal > jar</goal > </goals > </execution > </executions > </plugin > <plugin > <groupId > org.apache.maven.plugins</groupId > <artifactId > maven-assembly-plugin</artifactId > <version > 2.4</version > <configuration > <descriptors > <descriptor > ${project.basedir}/src/main/assembly/assembly.xml</descriptor > </descriptors > </configuration > <executions > <execution > <id > make-assembly</id > <phase > package</phase > <goals > <goal > single</goal > </goals > </execution > </executions > </plugin >
值得注意的地方如下几点:
mainClass
节点:用来指定启动main函数入口类路径
,如这里的:com.sm.EurekaServerApplication
excludes
节点:排除主jar包中配置等一些列后缀文件
,因为要包这些配置文件放到主包外面
descriptor
节点:用来指定assembly插件对应的assembly.xml
配置文件
完整pom.xml
文件内容:
<?xml version="1.0" encoding="UTF-8" ?> <project xmlns ="http://maven.apache.org/POM/4.0.0" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" > <modelVersion > 4.0.0</modelVersion > <parent > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-parent</artifactId > <version > 2.0.7.RELEASE</version > <relativePath /> </parent > <groupId > com.sm</groupId > <artifactId > eureka-server</artifactId > <version > 0.0.1</version > <name > eureka-server</name > <description > Demo project for Spring Boot</description > <properties > <java.version > 1.8</java.version > <spring-cloud.version > Finchley.SR2</spring-cloud.version > <scripts_packageName > ${project.artifactId}-${project.version}</scripts_packageName > <scripts_bootMain > com.sm.EurekaServerApplication</scripts_bootMain > </properties > <profiles > <profile > <id > node</id > <properties > <activeProfile > node</activeProfile > <package-name > ${scripts_packageName}</package-name > <boot-main > ${scripts_bootMain}</boot-main > </properties > <activation > <activeByDefault > true</activeByDefault > </activation > </profile > <profile > <id > node1</id > <properties > <activeProfile > node1</activeProfile > <package-name > ${scripts_packageName}</package-name > <boot-main > ${scripts_bootMain}</boot-main > </properties > </profile > <profile > <id > node2</id > <properties > <activeProfile > node2</activeProfile > <package-name > ${scripts_packageName}</package-name > <boot-main > ${scripts_bootMain}</boot-main > </properties > </profile > <profile > <id > node3</id > <properties > <activeProfile > node3</activeProfile > <package-name > ${scripts_packageName}</package-name > <boot-main > ${scripts_bootMain}</boot-main > </properties > </profile > </profiles > <dependencies > <dependency > <groupId > org.springframework.cloud</groupId > <artifactId > spring-cloud-starter-netflix-eureka-server</artifactId > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-test</artifactId > <scope > test</scope > </dependency > </dependencies > <dependencyManagement > <dependencies > <dependency > <groupId > org.springframework.cloud</groupId > <artifactId > spring-cloud-dependencies</artifactId > <version > ${spring-cloud.version}</version > <type > pom</type > <scope > import</scope > </dependency > </dependencies > </dependencyManagement > <build > <resources > <resource > <directory > ${project.basedir}/src/main/profiles/${activeProfile}</directory > </resource > <resource > <directory > ${project.basedir}/src/main/resources</directory > <includes > <include > static/**</include > <include > templates/**</include > </includes > </resource > </resources > <plugins > <plugin > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-maven-plugin</artifactId > <configuration > <includes > <include > <groupId > non-exists</groupId > <artifactId > non-exists</artifactId > </include > </includes > </configuration > <executions > <execution > <goals > <goal > repackage</goal > </goals > </execution > </executions > </plugin > <plugin > <groupId > org.apache.maven.plugins</groupId > <artifactId > maven-compiler-plugin</artifactId > <configuration > <source > 1.8</source > <target > 1.8</target > </configuration > </plugin > <plugin > <groupId > org.apache.maven.plugins</groupId > <artifactId > maven-jar-plugin</artifactId > <version > 2.6</version > <configuration > <archive > <addMavenDescriptor > false</addMavenDescriptor > <manifest > <addClasspath > true</addClasspath > <classpathPrefix > lib/</classpathPrefix > <mainClass > ${scripts_bootMain}</mainClass > </manifest > </archive > <excludes > <exclude > **/*.yml</exclude > <exclude > **/*.properties</exclude > <exclude > **/*.xml</exclude > <exclude > **/*.sh</exclude > </excludes > </configuration > <executions > <execution > <id > make-a-jar</id > <phase > compile</phase > <goals > <goal > jar</goal > </goals > </execution > </executions > </plugin > <plugin > <groupId > org.apache.maven.plugins</groupId > <artifactId > maven-assembly-plugin</artifactId > <version > 2.4</version > <configuration > <descriptors > <descriptor > ${project.basedir}/src/main/assembly/assembly.xml</descriptor > </descriptors > </configuration > <executions > <execution > <id > make-assembly</id > <phase > package</phase > <goals > <goal > single</goal > </goals > </execution > </executions > </plugin > </plugins > </build > </project >
有了上面pom.xml
配置,还需要assembly.xml
的配置,这里提取了结合shell脚本
发布程序的配置:
<assembly xmlns ="http://maven.apache.org/ASSEMBLY/2.0.0" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd http://maven.apache.org/ASSEMBLY/2.0.0 " > <id > ${activeProfile}</id > <formats > <format > zip</format > </formats > <includeBaseDirectory > false</includeBaseDirectory > <dependencySets > <dependencySet > <useProjectArtifact > false</useProjectArtifact > <outputDirectory > ${package-name}-${activeProfile}/lib</outputDirectory > <unpack > false</unpack > </dependencySet > </dependencySets > <fileSets > <fileSet > <directory > ${project.basedir}/src/main/profiles/${activeProfile}</directory > <outputDirectory > ${package-name}-${activeProfile}/conf</outputDirectory > <includes > <include > **/*</include > </includes > </fileSet > <fileSet > <directory > ${project.basedir}/src/main/scripts</directory > <outputDirectory > </outputDirectory > <includes > <include > **/*</include > </includes > <fileMode > 777</fileMode > <directoryMode > 777</directoryMode > <filtered > true</filtered > </fileSet > <fileSet > <directory > ${project.build.directory}</directory > <outputDirectory > ${package-name}-${activeProfile}/</outputDirectory > <includes > <include > *.jar</include > </includes > </fileSet > </fileSets > </assembly >
节点解析:
formats
节点:把配置文件和jar包等压缩成什么文件格式
,这里可以有:zip,tar等
fileMode
节点:指定scripts目录下脚本
文件(shenniu_publish.sh
)在linux上文件权限为777
filtered
节点:脚本中参数变量为pom.xml的profiles中properties的值
(该配置,是把pom.xml中属性值映射生成到sh文件中,如:${package-name})
完成上面配置后,此时可以通过idea上勾选切换不同环境来打zip包,如图:
shenniu_publish.sh程序启动工具 上面步骤完成了zip格式的发布包,再分享下启动程序的shell脚本,该脚本具有的功能
如下:
解压zip+启动jar包
启动jar包
停止对应jar运行
重启jar程序
目前该shell中封装了两种启动jar命令
的方式:
如图命令格式:
完整shell代码
:
#!/usr/bin/env bash languageType="javac" baseZipName="${package-name} -${activeProfile} " packageName="${package-name} " mainclass="${boot-main} " basePath=$(cd `dirname $0 `/; pwd ) baseZipPath="${basePath} /${baseZipName} .zip" baseDirPath="${basePath} " pid= function shenniu_unzip (){ echo "解压---------------------------------------------" echo "压缩包路径:${baseZipPath} " if [ ! `find ${baseZipPath} ` ] then echo "不存在压缩包:${baseZipPath} " else echo "解压磁盘路径:${baseDirPath} /${baseZipName} " echo "开始解压..." unzip -od ${baseDirPath} /${baseZipName} ${baseZipPath} chmod +x ${baseDirPath} /${baseZipName} /${packageName} echo "解压完成。" fi } function getPid (){ echo "检测状态---------------------------------------------" pid=`ps -ef | grep -n ${packageName} | grep -v grep | awk '{print $2}' ` if [ ${pid} ] then echo "运行pid:${pid} " else echo "未运行" fi } function start (){ stop if [ ${pid} ] then echo "停止程序失败,无法启动" else echo "启动程序---------------------------------------------" read -p "输入程序类型(java,javac,netcore),下一步按回车键(默认:${languageType} ):" read_languageType if [ ${read_languageType} ] then languageType=${read_languageType} fi echo "选择程序类型:${languageType} " cd ${baseDirPath} /${baseZipName} if [ "${languageType} " == "javac" ] then if [ ${mainclass} ] then nohup java -cp conf:lib\*.jar:${packageName} .jar ${mainclass} >${baseDirPath} /${packageName} .out 2>&1 & fi elif [ "${languageType} " == "java" ] then nohup java -jar ${baseDirPath} /${baseZipName} /${packageName} .jar >/dev/null 2>&1 & elif [ "${languageType} " == "netcore" ] then nohup ${baseDirPath} /${baseZipName} /${packageName} >/dev/null 2>&1 & fi getPid if [ ${pid} ] then echo "已启动" tail -n 50 -f ${baseDirPath} /${packageName} .out else echo "启动失败" fi fi } function stop (){ getPid if [ ${pid} ] then echo "停止程序---------------------------------------------" kill -9 ${pid} getPid if [ ${pid} ] then echo "停止失败" else echo "停止成功" fi fi } if [ ${#} -ge 1 ] then case ${1} in "start" ) start ;; "restart" ) start ;; "stop" ) stop ;; "unzip" ) shenniu_unzip start ;; *) echo "${1} 无任何操作" ;; esac else echo " command如下命令: unzip:解压并启动 start:启动 stop:停止进程 restart:重启 示例命令如:./shenniu_publish start " fi
shell中的参数package-name,activeProfile,boot-main
都是由pom.xml中profiles的properties中提供
,是可变的参数
,脚本代码本身不需要人工去修改
,只需要变的是pom.xml的参数即可
;其实在生成zip包的时候,shell中的参数就被替换了,可以看zip中shell文件内容如下:
linux上使用shenniu_publish.sh启动程序 把生成的zip上传到linux上,通过命令解压:
unzip -od eureka-server-0.0.1-node eureka-server-0.0.1-node.zip
其实shell脚本中包含有解压命令,但是在打包时放在了zip中,所以只能通过手动解压了,当然可以调整
;此时进入解压目录如此:
注
:这里第一次执行./shenniu_publish.sh
脚本时候,提示了错误信息是由于是在windows上编辑的这个脚本,其空格等和linux上不一样,所以运行会有问题
,要解决可以使用vim命令在linux把该文件转成linux格式
,如下命令:
vim shenniu_publish.sh set ff=unix:wq
执行完后,再来运行脚本./shenniu_publish.sh
,此时有如下提示:
此刻文件是解压状态
,因此只需要start命令启动程序即可:
到这里shenniu_publish.sh脚本使用就完成了
,只要脚本没有提示错误,基本都能启动jar服务;其他restart和stop命令也如此执行
就行: